/**
 * main module
 *
 * @author strlst <e11907086@student.tuwien.ac.at>
 * @date 2020-11-10
 * @brief the context in which the generator module is set up and subsequently used, additionally handles arguments and prints error information
 * @details none
 */

#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

#include "util.h"
#include "generator.h"

#define INCORRECT_USAGE 1
#define DEBUG           (0)

/**
 * @brief exits with specified exit_code after printing a specified message
 * @details message assumes a format specifier for the string 'program' parameter, assumes g has not been freed yet
 * @param message string containing the message to be printed
 * @param program string containing the program name
 * @param exit_code exit code, defined in "def.h"
 * @param g graph to free unconditionally
 */
static inline void die(char* message, char* program, int exit_code, struct graph *g) {
    free(g);
    fprintf(stderr, message, program, strerror(errno));
    exit(exit_code);
}

/**
 * @brief kills program while printing terminating message
 * @details prints usage string before exiting using exit(...)
 */
void usage() {
    fprintf(stderr, "usage: osue-3col-gen [edge...]\n\
  edge   specifies a connection between two nodes in a graph, specified like n-m, where n and m must be non-negative integers\n");
    exit(INCORRECT_USAGE);
}

/**
 * @brief parses arguments, initiates generator and handles exit codes
 * @details uses exit codes defined in "def.h"
 * @param argc argument count
 * @param argv argument vector
 */
int main(int argc, char **argv) {
    /* check for presence of edges */
    if (argc < 2)
        usage();

    /* generate graph */
    struct graph *g = malloc(sizeof *g);
    init_graph(g);

    /* process edges */
    if (extract_edges(g, optind, argc, argv) != OS_SUCCESS) {
        free(g);
        usage();
    }

    /* process nodes */
    extract_nodes(g);

    /* no output when not debugging */
    if (!DEBUG)
        fclose(stdout);

    /* initiate problem solving and print error in case one occurs*/
    switch (generate_solutions_setup(g)) {
        case OS_SHM_OPEN_FAILED:
            die("%s: error open shared memory: %s\n", argv[0], OS_SHM_OPEN_FAILED, g);
        case OS_SHM_CLOSE_FAILED:
            die("%s: error closing shared memory: %s\n", argv[0], OS_SHM_CLOSE_FAILED, g);
        case OS_MAP_FAILED:
            die("%s: error mapping shared memory: %s\n", argv[0], OS_MAP_FAILED, g);
        case OS_UNMAP_FAILED:
            die("%s: error unmapping shared memory: %s\n", argv[0], OS_UNMAP_FAILED, g);
        case OS_SEM_OPEN_FAILED:
            die("%s: error opening semaphore: %s\n", argv[0], OS_SEM_OPEN_FAILED, g);
        case OS_SEM_CLOSE_FAILED:
            die("%s: error closing semaphore: %s\n", argv[0], OS_SEM_CLOSE_FAILED, g);
        default:
            /* free graph */
            free(g);
    }

    return 0;
}
